package com.hollowlatte.manage.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hollowlatte.common.exceptionhandler.CustomException;
import com.hollowlatte.manage.entity.Role;
import com.hollowlatte.manage.entity.User;
import com.hollowlatte.manage.entity.UserRole;
import com.hollowlatte.manage.entity.vo.UserVO;
import com.hollowlatte.manage.mapper.RoleMapper;
import com.hollowlatte.manage.mapper.UserMapper;
import com.hollowlatte.manage.mapper.UserRoleMapper;
import com.hollowlatte.manage.service.UserService;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Hollow Latte
 * @since 2021-04-27
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    private final UserMapper userMapper;

    private final RoleMapper roleMapper;

    private final UserRoleMapper userRoleMapper;

    public UserServiceImpl(UserMapper userMapper, RoleMapper roleMapper, UserRoleMapper userRoleMapper) {
        this.userMapper = userMapper;
        this.roleMapper = roleMapper;
        this.userRoleMapper = userRoleMapper;
    }


    @Override
    public boolean assignRoleForUser(Long userId, Long roleId) {
        User user = userMapper.selectById(userId);
        Role role = roleMapper.selectById(roleId);
        if (ObjectUtils.isEmpty(role)) {
            throw new CustomException("A0400", "角色不存在");
        }
        if (ObjectUtils.isEmpty(user)) {
            throw new CustomException("A0400", "用户不存在");
        }

        UserRole userRole = new UserRole();
        userRole.setUserId(userId);
        userRole.setRoleId(roleId);

        if (!ObjectUtils.isEmpty(userRoleMapper.selectByUserIdAndRoleId(userId, roleId))) {
            throw new CustomException("A0400", "重复添加已拥有角色");
        }
        int affect = userRoleMapper.insert(userRole);
        return affect != 0;
    }


    @Override
    public boolean saveUser(Long userId, String password) {
        if (!ObjectUtils.isEmpty(userMapper.selectById(userId))) {
            throw new CustomException("A0400", "用户已存在");
        }
        User user = new User();
        // 利用UUID生成长度为8的盐值
        String salt = UUID.randomUUID().toString().substring(0, 8);
        user.setId(userId);
        user.setSalt(salt);
        // MD5加salt加密码
        Md5Hash md5Hash = new Md5Hash(password, salt, 1024);
        user.setPassword(md5Hash.toHex());

        int affect = userMapper.insert(user);

        return affect != 0;
    }


    @Override
    public boolean updatePassword(User user) {
        if (ObjectUtils.isEmpty(userMapper.selectById(user.getId()))) {
            throw new CustomException("A0400", "用户不存在");
        }
        // 利用UUID生成长度为8的盐值
        String salt = UUID.randomUUID().toString().substring(0, 8);
        user.setSalt(salt);
        // MD5加salt加密码
        Md5Hash md5Hash = new Md5Hash(user.getPassword(), salt, 1024);
        user.setPassword(md5Hash.toHex());

        int affect = userMapper.updateById(user);
        return affect != 0;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateRoleForUser(Long userId, List<Long> newRoleIdList) {
        if (ObjectUtils.isEmpty(userMapper.selectById(userId))) {
            throw new CustomException("A0400", "用户不存在");
        }
        for (Long roleId : newRoleIdList) {
            if (ObjectUtils.isEmpty(roleMapper.selectById(roleId))) {
                throw new CustomException("A0400", "角色不存在");
            }
        }

        userRoleMapper.deleteByUserId(userId);

        for (Long roleId : newRoleIdList) {
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(roleId);
            userRoleMapper.insert(userRole);
        }
        return true;
    }


    @Override
    public boolean removeRoleOfUser(Long userId, Long roleId) {
        int affect = userRoleMapper.deleteByUserIdAndRoleId(userId, roleId);
        return affect != 0;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeUser(Long userId) {
        // 删除user表内的用户（物理删除）
        int affect1 = userMapper.deleteById(userId);

        // 删除user_role表内的对应关系（物理删除）
        int affect2 = userRoleMapper.deleteByUserId(userId);

        return affect1 != 0 && affect2 != 0;
    }


    @Override
    public List<Role> listRoleById(Long userId) {
        return userMapper.selectRoleById(userId);
    }


    @Override
    public List<User> listByRoleId(Long roleId) {
        List<Long> userIds = userRoleMapper.selectByRoleId(roleId).stream().map(UserRole::getUserId).collect(Collectors.toList());

        return userMapper.selectBatchIds(userIds);
    }


    @Override
    public List<UserVO> convertUserToUserVO(List<User> userList) {
        List<UserVO> userVOList = new ArrayList<>();
        for (User user : userList) {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user, userVO);

            List<Long> roleIdList = userMapper.selectRoleById(user.getId())
                    .stream()
                    .map(Role::getId)
                    .collect(Collectors.toList());
            userVO.setRoleIdList(roleIdList);
            userVOList.add(userVO);
        }
        return userVOList;
    }


    @Override
    public UserVO convertUserToUserVO(User user) {
        List<User> userList = new ArrayList<>();
        userList.add(user);
        return convertUserToUserVO(userList).get(0);
    }
}
